package com.fuyao.cloud.common.data.resolver;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import com.fuyao.cloud.admin.api.dto.SysNumberDTO;
import com.fuyao.cloud.admin.api.feign.RemoteNumberService;
import com.fuyao.cloud.common.core.util.R;
import com.fuyao.cloud.common.core.util.SpringContextHolder;
import lombok.experimental.UtilityClass;

import java.util.Date;
import java.util.Map;
import java.util.Random;

/**
 * @author cloud
 * @date 2020/5/12
 * <p>
 * <p>
 * 编码码生成器，生成编码，
 * 2位单号类型+17位时间戳+8位(用户id加密&随机数)
 * 2位单号类型+8位时间戳+8位(用户id加密&随机数)
 *
 * <p>
 * 编码配置解析器
 */
@UtilityClass
public class NumberResolver {

	/**
	 * 随即编码
	 */

	private static final int[] r = new int[]{7, 9, 6, 2, 8, 1, 3, 0, 5, 4};

	/**
	 * 生成编码(调用方法) 生成规则 类型编码+8位时间戳+8位(用户id加密&随机数)
	 *
	 * @param numberType 编号类型
	 * @param userId     网站中该用户唯一ID 防止重复
	 * @param maxLength  编码随机数长度
	 */
	public static String getCodeByDate(String numberType, Integer userId, int maxLength) {
		return numberType + getCodeByDate(userId, maxLength);
	}

	/**
	 * 生成编码(调用方法)生成规则 类型编码+17位时间戳+8位(用户id加密&随机数)
	 *
	 * @param numberType 编号类型
	 * @param userId     网站中该用户唯一ID 防止重复
	 * @param maxLength  编码随机数长度
	 */
	public static String getCodeByDateTime(String numberType, Integer userId, int maxLength) {
		return numberType + getCodebyDateTime(userId, maxLength);
	}

	/**
	 * 生成编码(调用方法)生成规则 类型编码+17位时间戳+8位(用户id加密&随机数)
	 *
	 * @param numberType 编号类型
	 * @param userId     网站中该用户唯一ID 防止重复
	 * @param maxLength  编码随机数长度
	 */
	public static String getCodeByDateTime(String numberType, Long userId, int maxLength) {
		return numberType + getCodebyDateTime(userId, maxLength);
	}

	/**
	 * 根据类型+编码查询返回对应的数值 例：1
	 *
	 * @param type 类型
	 * @param code 编码
	 * @return 对应数值
	 */
	public static R<Long> getNumberValue(String type, String code) {
		SysNumberDTO sysNumberDTO = SysNumberDTO.builder().numbertype(type).code(code).build();
		return getRemoteNumberService().getNumberValue(sysNumberDTO);
	}

	/**
	 * 根据类型+编码 获取组装后的编码 例： xx.0001
	 *
	 * @param type 类型
	 * @param code 编码
	 * @return 对应数值
	 */
	public static R<String> getNumberStr(String type, String code) {
		SysNumberDTO sysNumberDTO = SysNumberDTO.builder().numbertype(type).code(code).build();
		return getRemoteNumberService().getNumberStr(sysNumberDTO);
	}

	/**
	 * 根据类型+编码 获取组装后的编码 例： xx.0001
	 *
	 * @param type 类型
	 * @param code 编码
	 * @param num  格式化位数
	 * @return 对应数值
	 */
	public static R<String> getNumberStr(String type, String code, Long num) {
		SysNumberDTO sysNumberDTO = SysNumberDTO.builder().numbertype(type).code(code).num(num).build();
		return getRemoteNumberService().getNumberStr(sysNumberDTO);
	}

	/**
	 * 根据类型+编码 获取组装后 map 集合包含 value:数值 code：数据格式化值 codeValue:编码+数值格式化
	 * @param type 类型
	 * @param code 编码
	 * @param num 格式化位数
	 * @return map 集合
	 */
	public static R<Map<String,String>> getNumberMap(String type,String code,Long num){
		SysNumberDTO sysNumberDTO = SysNumberDTO.builder().numbertype(type).code(code).num(num).build();
		return getRemoteNumberService().getNumberMap(sysNumberDTO);
	}

	/**
	 * 根据父级编码+类型+编码 获取组装后的编码 例： xx.xx.0001
	 *
	 * @param parentCode 父级编码
	 * @param type       类型
	 * @param code       编码
	 * @return 对应数值
	 */
	public static R getNumberParentJoinCodeStr(String parentCode, String type, String code) {
		SysNumberDTO sysNumberDTO = SysNumberDTO.builder().parentCode(parentCode).numbertype(type).code(code).build();
		return getRemoteNumberService().getServerNumberJoinParent(sysNumberDTO);
	}

	/**
	 * 根据父级编码+类型+编码 获取组装后的编码 例： xx.xx.0001
	 *
	 * @param parentCode 父级编码
	 * @param type       类型
	 * @param code       编码
	 * @param num        格式化位数
	 * @return 对应数值
	 */
	public static R getNumberParentJoinCodeStr(String parentCode, String type, String code, Long num) {
		SysNumberDTO sysNumberDTO = SysNumberDTO.builder().parentCode(parentCode).numbertype(type).code(code).num(num).build();
		return getRemoteNumberService().getServerNumberJoinParent(sysNumberDTO);
	}


	//---------------------------------------------公/私有方法分隔线------------------------------------------------

	/**
	 * 根据id进行加密+加随机数组成固定长度编码
	 *
	 * @param userId    用户ID
	 * @param maxLength 编码随机数长度
	 */
	private static String toCode(Integer userId, int maxLength) {
		String idStr = String.valueOf(userId);
		StringBuilder idsbs = new StringBuilder();
		for (int i = idStr.length() - 1; i >= 0; i--) {
			idsbs.append(r[idStr.charAt(i) - '0']);
		}
		return idsbs.append(getRandom(maxLength - idStr.length())).toString();
	}

	/**
	 * 根据id进行加密+加随机数组成固定长度编码
	 *
	 * @param userId    用户ID
	 * @param maxLength 编码随机数长度
	 */
	private static String toCode(Long userId, int maxLength) {
		String idStr = String.valueOf(userId);
		StringBuilder idsbs = new StringBuilder();
		for (int i = idStr.length() - 1; i >= 0; i--) {
			idsbs.append(r[idStr.charAt(i) - '0']);
		}
		return idsbs.append(getRandom(maxLength - idStr.length())).toString();
	}

	/**
	 * 生成时间戳 yyyyMMddHHmmssSSS
	 */
	private static String getDateTime() {
//		DateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmssSSS");
		return DateUtil.format(new Date(), DatePattern.PURE_DATETIME_PATTERN);
	}

	/**
	 * 生成时间戳 yyyyMMdd
	 */
	private static String getDate() {
//		DateFormat sdf = new SimpleDateFormat("yyyyMMdd");
		return DateUtil.format(new Date(),DatePattern.PURE_DATE_PATTERN);
	}

	/**
	 * 生成固定长度随机码
	 *
	 * @param n 长度
	 */

	private static long getRandom(long n) {
		long min = 1, max = 9;
		for (int i = 1; i < n; i++) {
			min *= 10;
			max *= 10;
		}
		return (((long) (new Random().nextDouble() * (max - min)))) + min;
	}


	/**
	 * 生成不带类别标头的编码
	 *
	 * @param userId    用户ID
	 * @param maxLength 编码随机数长度
	 */
	private static synchronized String getCodebyDateTime(Integer userId, int maxLength) {
		userId = userId == null ? 10000 : userId;
		return getDateTime() + toCode(userId, maxLength);
	}

	/**
	 * 生成不带类别标头的编码
	 *
	 * @param userId    用户ID
	 * @param maxLength 编码随机数长度
	 */
	private static synchronized String getCodebyDateTime(Long userId, int maxLength) {
		userId = userId == null ? 10000 : userId;
		return getDateTime() + toCode(userId, maxLength);
	}

	/**
	 * 生成不带类别标头的编码
	 *
	 * @param userId    用户ID
	 * @param maxLength 编码随机数长度
	 */
	private static synchronized String getCodeByDate(Integer userId, int maxLength) {
		userId = userId == null ? 10000 : userId;
		return getDate() + toCode(userId, maxLength);
	}


	/**
	 * 获取路由service
	 *
	 * @return 编码路由service
	 */
	private RemoteNumberService getRemoteNumberService() {
		return SpringContextHolder.getBean(RemoteNumberService.class);
	}
}
